package io.github.talelin.latticy.service.oms.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.talelin.autoconfigure.exception.ForbiddenException;
import io.github.talelin.autoconfigure.exception.NotFoundException;
import io.github.talelin.latticy.common.LocalUser;
import io.github.talelin.latticy.common.enumeration.OrderStatusEnum;
import io.github.talelin.latticy.common.mybatis.Page;
import io.github.talelin.latticy.common.util.BeanUtils;
import io.github.talelin.latticy.common.util.SnowFlake;
import io.github.talelin.latticy.dto.omsware.OmsCheckDTO;
import io.github.talelin.latticy.dto.order.CreateOrderDTO;
import io.github.talelin.latticy.dto.order.OrderPageDTO;
import io.github.talelin.latticy.dto.order.PageListDTO;
import io.github.talelin.latticy.dto.order.TakeDownPageListDTO;
import io.github.talelin.latticy.dto.product.SelectProductDTO;
import io.github.talelin.latticy.feign.WmsWarehouseFeignClient;
import io.github.talelin.latticy.mapper.oms.OrderMapper;
import io.github.talelin.latticy.model.UserDO;
import io.github.talelin.latticy.model.oms.OrderDO;
import io.github.talelin.latticy.model.oms.OrderItemDO;
import io.github.talelin.latticy.model.oms.ProductDO;
import io.github.talelin.latticy.service.GroupService;
import io.github.talelin.latticy.service.oms.OrderItemService;
import io.github.talelin.latticy.service.oms.OrderService;
import io.github.talelin.latticy.service.oms.ProductService;
import io.github.talelin.latticy.vo.FindResultVO;
import io.github.talelin.latticy.vo.WarehouseVO;
import io.github.talelin.latticy.vo.oms.OrderDetailVO;
import io.github.talelin.latticy.vo.oms.OrderItemVO;
import io.github.talelin.latticy.vo.oms.OrderTakeDownPageListVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author generator@wulongbo
 * @since 2022-06-28
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderDO> implements OrderService {

    @Autowired
    private ProductService productService;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private GroupService groupService;

    @Autowired
    private WmsWarehouseFeignClient wmsWarehouseFeignClient;


    @Override
    public List<WarehouseVO> getOmsWarehouseById() {
        UserDO user = LocalUser.getLocalUser();
        if (user.getIsAdmin()) {
            return wmsWarehouseFeignClient.getAllWarehouseByOmsRoot();
        }
        List<WarehouseVO> list = wmsWarehouseFeignClient.getOmsWarehouseById(user.getId());
        Optional.ofNullable(list).orElseThrow(() -> new NotFoundException(18302));
        return list;
    }

    @Transactional
    @Override
    public boolean createOrder(CreateOrderDTO dto) {
        UserDO user = LocalUser.getLocalUser();
        // 校验仓库
        OmsCheckDTO checkDTO = new OmsCheckDTO(user.getId(), dto.getCode());
        boolean exist = wmsWarehouseFeignClient.checkWareExistByCode(checkDTO);
        if (!exist) {
            throw new ForbiddenException(18301);
        }
        List<SelectProductDTO> products = dto.getProducts();
        List<String> skus = products.stream().map(SelectProductDTO::getSku).collect(Collectors.toList());
        //根据商品id获取商品
        List<ProductDO> skuList = productService.getListBySkus(skus);
        if (products.size() != skuList.size()) {
            throw new ForbiddenException(15011);
        }
        //检查是否包含已下架商品
        this.checkSkus(skuList);
        //生成订单号
        SnowFlake idWorker = new SnowFlake(0, 0);
        Long orderNo = idWorker.nextId();
        // 生成订单
        OrderDO orderDO = new OrderDO(dto, orderNo);
        orderDO.setCreatorCode(LocalUser.getLocalUser().getUsername());
        orderDO.setStatus(OrderStatusEnum.DRAFT);
//        if (groupService.checkIsAdminByUserId(user.getId())) {
//            orderDO.setTenant(user.getId());
//        } else {
//            // root账号置空
//            if (!groupService.checkIsRootByUserId(user.getId())) {
//                orderDO.setTenant(user.getTenant());
//            }
//        }
        orderDO.setTenant(user.getTenant());
        this.save(orderDO);

        // 生成订单item
        Map<String, ProductDO> skuMap = skuList.stream().collect(Collectors.toMap(ProductDO::getSku, Function.identity(), (entity1, entity2) -> entity1));
        //生成所有的订单项快照，并保存至数据库
        List<OrderItemDO> orderItemList = products.parallelStream().map(p -> copyPropVO(skuMap.get(p.getSku()), p.getNum(), orderNo)).collect(Collectors.toList());
        //保存至数据库
        return orderItemService.saveBatch(orderItemList);
    }

    @Transactional
    @Override
    public boolean updateOrderByOrderNo(Long orderNo, CreateOrderDTO dto) {
        List<SelectProductDTO> products = dto.getProducts();
        List<String> skus = products.stream().map(SelectProductDTO::getSku).collect(Collectors.toList());
        //根据商品id获取商品
        List<ProductDO> skuList = productService.getListBySkus(skus);
        if (products.size() != skuList.size()) {
            throw new ForbiddenException(15011);
        }
        //检查是否包含已下架商品
        this.checkSkus(skuList);
        // 修改订单
        OrderDO orderDO = new OrderDO(dto, orderNo);
        this.updateById(orderDO);
        // 修改订单item
        orderItemService.deleteByOrderNo(orderNo);
        // 生成订单item
        Map<String, ProductDO> skuMap = skuList.stream().collect(Collectors.toMap(ProductDO::getSku, Function.identity(), (entity1, entity2) -> entity1));
        //生成所有的订单项快照，并保存至数据库
        List<OrderItemDO> orderItemList = products.parallelStream().map(p -> copyPropVO(skuMap.get(p.getSku()), p.getNum(), orderNo)).collect(Collectors.toList());
        //保存至数据库
        return orderItemService.saveBatch(orderItemList);
    }

    @Transactional
    @Override
    public boolean deleteByOrderNo(Long orderNo) {
        if (!this.checkExistByOrderNo(orderNo)) {
            throw new NotFoundException(21000);
        }
        OrderDO query = this.getById(orderNo);
        if (!(query.getStatus().equals(OrderStatusEnum.CANCELLED) || query.getStatus().equals(OrderStatusEnum.DRAFT))) {
            throw new ForbiddenException(21001);
        }
        this.baseMapper.deleteCancelOrderByOrderId(orderNo);
        return orderItemService.deleteByOrderNo(orderNo) > 0;
    }

    @Override
    public OrderDetailVO getByOrderNo(Long orderNo) {
        return this.baseMapper.getOrderDetailVOByOrderId(orderNo);
    }

    @Override
    public boolean approveOrder(Long orderNo) {
        if (!this.checkExistByOrderNo(orderNo)) {
            throw new NotFoundException(21000);
        }
        OrderDO query = this.getById(orderNo);
        if (!query.getStatus().equals(OrderStatusEnum.DRAFT)) {
            throw new ForbiddenException(21003);
        }
        List<OrderItemDO> orderItems = orderItemService.getListByOrderNo(orderNo);
        //判断商品库存
        for (OrderItemDO orderItemDO : orderItems) {
            //存在数量大于库存的情况，直接返回错误提醒
            /**
             if (orderItemDO.getProductNum() > wms库存) {
             String errorMsg = String.format("订单：%s 库存不足", skuMap.get(cartDto.getCode()).getTitle());
             throw new ForbiddenException(errorMsg);
             }
             */
        }
        OrderDO orderDO = new OrderDO();
        orderDO.setOrderNo(orderNo);
        orderDO.setStatus(OrderStatusEnum.APPROVED);
        return this.updateById(orderDO);
    }

    @Override
    public boolean cancelOrder(Long orderNo) {
        if (!this.checkExistByOrderNo(orderNo)) {
            throw new NotFoundException(21000);
        }
        OrderDO query = this.getById(orderNo);
        if (!query.getStatus().equals(OrderStatusEnum.DRAFT)) {
            throw new ForbiddenException(21002);
        }
        OrderDO orderDO = new OrderDO();
        orderDO.setOrderNo(orderNo);
        orderDO.setStatus(OrderStatusEnum.CANCELLED);
        return this.updateById(orderDO);
    }

    @Override
    public boolean recoveryOrder(Long orderNo) {
        if (!this.checkExistByOrderNo(orderNo)) {
            throw new NotFoundException(21000);
        }
        OrderDO query = this.getById(orderNo);
        if (!query.getStatus().equals(OrderStatusEnum.CANCELLED)) {
            throw new ForbiddenException(21004);
        }
        OrderDO orderDO = new OrderDO();
        orderDO.setOrderNo(orderNo);
        orderDO.setStatus(OrderStatusEnum.DRAFT);
        return this.updateById(orderDO);
    }

    @Override
    public boolean checkExistByOrderNo(Long orderNo) {
        QueryWrapper<OrderDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(OrderDO::getOrderNo, orderNo);
        return this.count(wrapper) > 0;
    }

    @Override
    public IPage<OrderDO> getOrdersPage(OrderPageDTO orderPageDTO) {
        UserDO user = LocalUser.getLocalUser();
        LambdaQueryWrapper<OrderDO> wrapper = new LambdaQueryWrapper<OrderDO>()
                .like(ObjectUtil.isNotNull(orderPageDTO.getOrderNo()), OrderDO::getOrderNo, orderPageDTO.getOrderNo())
                .or().like(StrUtil.isNotEmpty(orderPageDTO.getCode()), OrderDO::getWarehouseCode, orderPageDTO.getCode())
                .or().like(ObjectUtil.isNotEmpty(orderPageDTO.getStatus()), OrderDO::getStatus, orderPageDTO.getStatus())
                .or().like(ObjectUtil.isNotEmpty(orderPageDTO.getShipType()), OrderDO::getShipType, orderPageDTO.getShipType())
                ;
        if (groupService.checkIsAdminByUserId(user.getId())) {
            wrapper.eq(OrderDO::getTenant, user.getId());
        } else {
            if (!groupService.checkIsRootByUserId(user.getId())) {
                wrapper.eq(OrderDO::getTenant, user.getTenant());
            }
        }
        return this.baseMapper.selectPage(new Page<>(orderPageDTO.getPage(), orderPageDTO.getCount()), wrapper);
    }


    @Override
    public FindResultVO takeDownPageList(TakeDownPageListDTO pageListDTO) {
        Page page = new Page(pageListDTO.getCurrPage(), pageListDTO.getPageSize());
        IPage<OrderDetailVO> pageList = this.baseMapper.takeDownPageList(page, pageListDTO);
        // 查询一票一件 一票一件多个  一票多件
        Map<String, Long> itemPickingType = this.baseMapper.findItemPickingType();
        OrderTakeDownPageListVO build = OrderTakeDownPageListVO.builder().map(itemPickingType).pageList(pageList).build();
        return FindResultVO.success(build);
    }

    @Override
    public FindResultVO findById(Long id) {
        OrderDO orderDO = this.baseMapper.selectById(id);
        LambdaQueryWrapper<OrderItemDO> queryWrapper = Wrappers.lambdaQuery(OrderItemDO.class)
                .eq(OrderItemDO::getOrderNo,orderDO.getOrderNo());
        List<OrderItemDO> orderItemDOS = orderItemService.list(queryWrapper);
        List<OrderItemVO> collect = orderItemDOS.stream().map(orderItem -> BeanUtils.copyProperties(orderItem, OrderItemVO.class)).collect(Collectors.toList());
        OrderDetailVO orderDetailVO = BeanUtils.copyProperties(orderDO, OrderDetailVO.class);
        orderDetailVO.setOrderItems(new ArrayList<>(collect));
        return FindResultVO.success(orderDetailVO);
    }


    @Override
    public FindResultVO pageList(PageListDTO pageListDTO) {
        Page page = new Page(pageListDTO.getCurrPage(), pageListDTO.getPageSize());
        return FindResultVO.success(this.baseMapper.pageList(page, pageListDTO));
    }

    @Override
    public FindResultVO findByIds(List<Long> orderOns) {
        return FindResultVO.success(this.baseMapper.selectByIds(orderOns));
    }

    private OrderItemDO copyPropVO(ProductDO productDO, Integer num, Long orderNo) {
        OrderItemDO orderItemDO = new OrderItemDO();
        orderItemDO.setOrderNo(orderNo);
        orderItemDO.setSku(productDO.getSku());
        orderItemDO.setProductIcon(productDO.getPictureUrl());
        orderItemDO.setProductName(productDO.getName());
        orderItemDO.setProductNum(num);
        // 暂用这个价格
        orderItemDO.setProductPrice(productDO.getDeclarePrice());
        return orderItemDO;
    }

    private void checkSkus(List<ProductDO> skuList) {
        //检查是否包含已下架商品
        List<ProductDO> skuNotSelling = skuList.stream()
                .filter(t -> !t.getIsDisable()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(skuNotSelling)) {
            //skuNotSelling 对象非空则表示有下架商品
            String errorMsg = String.format("订单列表：%s 已下架，无法生成订单", skuNotSelling.get(0).getName());
            throw new ForbiddenException(errorMsg);
        }
    }
}
